#include "serverhandler.h"

#include <QJsonObject>
#include <QJsonDocument>
#include <QJsonArray>

#include <QDebug>

#include "socket.h"
#include "sqldao.h"
#include "room.h"
#include "roommanager.h"

/**
 * @brief ServerHandler::ServerHandler
 * @param socket
 */
ServerHandler::ServerHandler(Socket* socket)
{
    handlers = QVector<IHandler*>(last, nullptr);

    handlers[regist] = new ServerHandlerRegister(socket);
    handlers[login] = new ServerHandlerLogin(socket);
    handlers[chat] = new ServerHandlerChat(socket);
    handlers[createRoom] = new ServerHandlerCreateRoom(socket);
    handlers[joinRoom] = new ServerHandlerJoinRoom(socket);
    handlers[closeRoom] = new ServerHandlerCloseRoom(socket);
    handlers[getRoom] = new ServerHandlerGetRoom(socket);
    handlers[audioTrans] = new ServerHandlerAudioTrans(socket);
    handlers[videoTrans] = new ServerHandlerVideoTrans(socket);
}

/*
 * @brief:
 * @detail:
 */
void ServerHandler::reset()
{
    for(auto handler : handlers) if(handler) {handler->reset();}
}

/**
 * @brief Register::handle
 * @param data
 */
void ServerHandlerRegister::handle(const QByteArray& data)
{
    // 注册处理
    QJsonObject json = QJsonDocument::fromJson(data).object();

    QString username = json["username"].toString();
    QString password = json["password"].toString();

    // 注册处理
    // 1. 数据库插入成功 -> 注册成功 失败 -> 注册失败
    json = QJsonObject();

    QString ret = SqlDao::selectUser(username);

    if(!ret.isEmpty()){
        // 没找到
        json["result"] = "failed";
    }
    else
    {
        if(SqlDao::insertUser(username, password))
        {
            json["result"] = "success";
        }
        else
        {
            json["result"] = "failed";
        }
    }

    socket->write(Streamer::pack(Handler::regist, QJsonDocument(json).toJson()));
}

/**
 * @brief Login::handle
 * @param data
 */
void ServerHandlerLogin::handle(const QByteArray& data)
{
    // 登录处理
    QJsonObject json = QJsonDocument::fromJson(data).object();

    QString username = json["username"].toString();
    QString password = json["password"].toString();

    // 登录处理

    // 1. 查询
    json = QJsonObject();
    QString ret = SqlDao::selectUser(username);

    do{
        if(ret.isEmpty()){
            // 没找到
            json["result"] = "failed";
            json["info"] = "can't find user";
            break;
        }

        if(ret != password){
            // 密码错误
            json["result"] = "failed";
            json["info"] = "wrong password";
            break;
        }

        if(SingleTon<ServerLoginManager>::getReference().loginManager.find(username)
                != SingleTon<ServerLoginManager>::getReference().loginManager.end()){
            json["result"] = "failed";
            json["info"] = "conflicted login";
            break;
        }

        // 登录成功
        json["username"] = username;
        json["result"] = "success";
        json["info"] = "login success";

        u = username;
        SingleTon<ServerLoginManager>::getReference().loginManager[username] = socket;
        socket->setUserName(username);
    }while(0);

    socket->write(Streamer::pack(Handler::login, QJsonDocument(json).toJson()));
}

/**
 * @brief Login::reset
 */
void ServerHandlerLogin::reset()
{
    // 如果当前套接字所绑定的用户已经登录，则需要去除登录状态
    if(u.isEmpty() == false){
        SingleTon<ServerLoginManager>::getReference().loginManager.remove(u);
    }
}

/**
 * @brief Chat::handle
 * @param data
 */
void ServerHandlerChat::handle(const QByteArray& data)
{
    QJsonObject json = QJsonDocument::fromJson(data).object();
    QString username = json["username"].toString();
    QString roomid = socket->getRoom();
    QString message = json["message"].toString();

    QByteArray data1 = QJsonDocument(json).toJson();
    SingleTon<RoomManager>::getReference().getRoom(roomid)->chatBroadcast(&data1);
}

/**
 * @brief CreateRoom::handle
 * @param data
 * @details
 */
void ServerHandlerCreateRoom::handle(const QByteArray &data)
{

    // 创建房间处理
    QJsonObject json = QJsonDocument::fromJson(data).object();

    QString username = json["username"].toString();
    QString roomid = json["roomid"].toString();

    json = QJsonObject();
    //查重
    QMap<QString,Room*>& room = SingleTon<RoomManager>::getReference().getRooms();

    if(room[roomid] != nullptr)
    {
        json["result"] = "failed";
        json["info"] = "failed create room";
    }
    else
    {// 创建成功
        //记录该套接字的房间
        socket->setRoom(roomid);

        SingleTon<RoomManager>::getReference().appendRoom(roomid,username,socket);
        json["result"] = "success";
        json["info"] = "create room";
        qDebug()<<username<<" create room "<<roomid;
    }

    json["anchor"]=username;
    json["roomid"] = roomid;

    socket->write(Streamer::pack(Handler::createRoom, QJsonDocument(json).toJson()));
}

/**
 * @brief JoinRoom::handle
 * @param data
 */
void ServerHandlerJoinRoom::handle(const QByteArray &data)
{
    QJsonObject json = QJsonDocument::fromJson(data).object();
    QString username = json["username"].toString();
    QString roomid = json["roomid"].toString();

    QMap<QString,Room*> room = SingleTon<RoomManager>::getReference().getRooms();
    if(room[roomid]!=nullptr)
    {
        json["result"] = "success";
        //记录该套接字的房间
        socket->setRoom(roomid);
    }
    else
    {
        json["result"] = "failed";
        socket->write(Streamer::pack(Handler::joinRoom,QJsonDocument(json).toJson()));
        return;
    }


    QByteArray data1=QJsonDocument(json).toJson();
    Room* curRoom = SingleTon<RoomManager>::getReference().getRoom(roomid);
    curRoom->addAudiBroadcast(&data1);
    curRoom->addAudience(socket);

    //使用QJsonArray保存观众名字集合
    QJsonArray audi;
    for(auto s : curRoom->getAudienceNames())
        audi.append(QJsonValue(s));
    json["list"] = audi;

    json["anchor"] = curRoom->getRoomHost();
    data1=QJsonDocument(json).toJson();
    socket->write(Streamer::pack(Handler::joinRoom,data1));

    qDebug()<<username<<" join in "<<roomid<<" room";
}

/**
 * @brief ServerHandlerCloseRoom::handle
 * @param data
 */
void ServerHandlerCloseRoom::handle(const QByteArray &data)
{
    QJsonObject json = QJsonDocument::fromJson(data).object();
    QString username = json["username"].toString();
    QString roomid = socket->getRoom();
    //去除该套接字房间
    socket->clearRoom();

    closeroom(username,roomid,socket);
}

void ServerHandlerCloseRoom::closeroom(QString& username, QString& roomid, Socket* socket)
{
    Room* curRoom = SingleTon<RoomManager>::getReference().getRoom(roomid);
    if(curRoom==nullptr) {return;}
    //判断是否是主播,若是则群播下线,若观众则列表中删除观众
    if(username == curRoom->getRoomHost())
    {
        //通知观众主播下线
        QJsonObject json = QJsonObject();
        json["result"]= "off";
        json["info"] = "Anchor off";
        QByteArray data = QJsonDocument(json).toJson();
        curRoom->offBroadcast(&data);
        //删除房间
        SingleTon<RoomManager>::getReference().removeRoom(roomid);
        qDebug()<<" room "<<roomid<<" offline ";

    }
    else
    {
        //该房间观众列表删除该观众
        curRoom->deleAudience(socket);
        qDebug()<<username<<" offline ";
    }
}

/**
 * @brief ServerHandlerGetRoom::handle
 * @param data
 */
void ServerHandlerGetRoom::handle(const QByteArray &data)
{
    Q_UNUSED(data);
    QJsonObject json = QJsonObject();
    //将在线room列表传给客户端
    QMap<QString,Room*> rooms = SingleTon<RoomManager>::getReference().getRooms();
    QMap<QString,Room*>::Iterator it;
    if(!rooms.isEmpty())
    {
        for(it = rooms.begin();it != rooms.end(); ++it)
        {
            if(it.value()!=nullptr)
            {json[it.key()]=it.value()->getRoomID();}
        }
    }
    else
    {
        json["result"]="no rooms";
    }

    socket->write(Streamer::pack(Handler::getRoom, QJsonDocument(json).toJson()));
}

/**
 * @brief ServerHandlerAudioTrans::handle
 * @param data
 */
void ServerHandlerAudioTrans::handle(const QByteArray &data)
{
    QString roomid = socket->getRoom();
    Room* room = SingleTon<RoomManager>::getReference().getRoom(roomid);
    if(room==nullptr){return;}
    room->audioBroadcast(data);
}

/**
 * @brief ServerHandlerVideoTrans::handle
 * @param data
 */
void ServerHandlerVideoTrans::handle(const QByteArray &data)
{
    QString roomid = socket->getRoom();
    Room* room = SingleTon<RoomManager>::getReference().getRoom(roomid);
    if(room==nullptr){return;}
    room->videoBroadcast(socket,data);
}

